"""
简历管理相关的异步任务
"""
import logging
import time
import os
from celery import shared_task
from celery.exceptions import Retry, SoftTimeLimitExceeded
from django.utils import timezone
from django.core.files.base import ContentFile
from django.db import transaction
from .models import Resume
from .dify_service import dify_service, DifyAPIError
from students.models import Student
from jobs.models import Job

logger = logging.getLogger(__name__)


def send_evaluation_notification(student_user, resume, job, status, error_msg=None):
    """
    发送AI评估通知的辅助函数

    Args:
        student_user: 学生用户对象
        resume: 简历对象
        job: 岗位对象
        status: 评估状态 ('completed' 或 'failed')
        error_msg: 错误信息（可选）
    """
    try:
        from notifications.services import NotificationService
        if student_user:
            NotificationService.create_ai_evaluation_notification(
                student_user, resume, job, status, error_msg
            )
            logger.info(f"评估通知发送成功 - Resume ID: {resume.id}, Status: {status}")
        else:
            logger.warning(f"无法发送通知，学生没有关联用户 - Student ID: {resume.student.id}")
    except Exception as e:
        logger.error(f"发送评估通知失败 - Resume ID: {resume.id}, Status: {status}, Error: {str(e)}")





def _extract_resume_content(resume):
    """
    提取简历内容的辅助函数

    Args:
        resume: 简历对象

    Returns:
        str: 提取的简历内容
    """
    try:
        # 方式1：获取结构化内容
        content = resume.get_structured_content()
        if content and len(content.strip()) > 20:
            return content

        # 方式2：从基础信息构建
        basic_info = getattr(resume, 'basic_info', None)
        if basic_info:
            content_parts = []

            # 基本信息
            if basic_info.name:
                content_parts.append(f"姓名：{basic_info.name}")
            if basic_info.phone:
                content_parts.append(f"电话：{basic_info.phone}")
            if basic_info.email:
                content_parts.append(f"邮箱：{basic_info.email}")
            if basic_info.school:
                content_parts.append(f"学校：{basic_info.school}")
            if basic_info.major:
                content_parts.append(f"专业：{basic_info.major}")
            if basic_info.education_level:
                content_parts.append(f"学历：{basic_info.education_level}")
            if basic_info.graduation_date:
                content_parts.append(f"毕业时间：{basic_info.graduation_date}")

            # 教育经历
            education_set = getattr(resume, 'education_set', None)
            if education_set:
                for edu in education_set.all():
                    content_parts.append(f"教育经历：{edu.school} - {edu.major}")

            # 工作经历
            workexperience_set = getattr(resume, 'workexperience_set', None)
            if workexperience_set:
                for work in workexperience_set.all():
                    content_parts.append(f"工作经历：{work.company} - {work.position}")

            # 项目经历
            project_set = getattr(resume, 'project_set', None)
            if project_set:
                for project in project_set.all():
                    content_parts.append(f"项目经历：{project.name}")

            # 技能
            skill_set = getattr(resume, 'skill_set', None)
            if skill_set:
                skills = [skill.name for skill in skill_set.all()]
                if skills:
                    content_parts.append(f"技能：{', '.join(skills)}")

            if content_parts:
                return '\n'.join(content_parts)

        # 方式3：从上传文件提取
        if resume.uploaded_file:
            try:
                file_path = resume.uploaded_file.path
                if os.path.exists(file_path):
                    # 使用dify_service的文件提取功能
                    content = dify_service._extract_file_content(file_path)
                    if content and len(content.strip()) > 20:
                        return content
            except Exception as e:
                logger.warning(f"从上传文件提取内容失败: {e}")

        return ""

    except Exception as e:
        logger.error(f"提取简历内容失败: {e}")
        return ""


@shared_task(bind=True, max_retries=3, default_retry_delay=60, time_limit=600, soft_time_limit=540)
def ai_evaluation_task(self, resume_id, job_id, user_id):
    """
    异步执行AI简历评估任务

    Args:
        resume_id: 简历ID
        job_id: 岗位ID
        user_id: 用户ID（格式：student_{student_id}）

    Returns:
        dict: 评估结果
    """
    start_time = time.time()
    task_id = self.request.id
    logger.info(f"开始AI评估任务 - Resume ID: {resume_id}, Task ID: {task_id}")

    resume = None
    job = None
    student_user = None

    try:
        # 获取简历和岗位信息
        try:
            resume = Resume.objects.select_related('student', 'student__user').get(id=resume_id)
            job = Job.objects.select_related('company').get(id=job_id)
            student_user = resume.student.user if hasattr(resume.student, 'user') else None
        except Resume.DoesNotExist:
            error_msg = f"简历不存在 - Resume ID: {resume_id}"
            logger.error(error_msg)
            return {'error': error_msg}
        except Job.DoesNotExist:
            error_msg = f"岗位不存在 - Job ID: {job_id}"
            logger.error(error_msg)
            return {'error': error_msg}

        logger.info(f"开始AI评估 - 简历: {resume.title}, 学生: {resume.student.name}, 岗位: {job.title}")
        logger.info(f"评估参数 - Resume ID: {resume_id}, Job ID: {job_id}, User ID: {user_id}")
        logger.info(f"当前评估状态: {resume.ai_evaluation_status}")

        # 检查简历状态，防止重复评估
        if resume.ai_evaluation_status == 'completed':
            logger.info(f"简历已完成评估 - Resume ID: {resume_id}")
            # 确保发送通知
            send_evaluation_notification(student_user, resume, job, 'completed')
            return {
                'success': True,
                'message': '简历已完成评估',
                'evaluation_status': resume.ai_evaluation_status
            }

        # 更新任务状态
        with transaction.atomic():
            resume.ai_evaluation_status = 'in_progress'
            resume.ai_evaluation_error = None
            resume.save()

        # 提取简历内容
        logger.info("开始提取简历内容")
        logger.info(f"简历类型: {resume.resume_type}")
        logger.info(f"是否有上传文件: {bool(resume.uploaded_file)}")

        resume_content = _extract_resume_content(resume)

        # 检查简历内容
        logger.info(f"简历内容提取完成，长度: {len(resume_content) if resume_content else 0}")

        if not resume_content or len(resume_content.strip()) < 20:
            error_msg = f"简历内容为空或过短（{len(resume_content) if resume_content else 0}字符），无法进行评估"
            logger.error(f"{error_msg} - Resume ID: {resume_id}")
            logger.error(f"简历内容预览: {resume_content[:100] if resume_content else 'None'}")

            # 更新失败状态
            with transaction.atomic():
                resume.ai_evaluation_status = 'failed'
                resume.ai_evaluation_error = error_msg
                resume.save()

            # 发送失败通知
            send_evaluation_notification(student_user, resume, job, 'failed', error_msg)

            return {'error': error_msg}

        logger.info(f"简历内容提取成功，长度: {len(resume_content)}")
        logger.info(f"简历内容预览: {resume_content[:200]}...")

        # 获取简历文件路径（如果有上传文件）
        resume_file_path = None
        if resume.uploaded_file:
            try:
                resume_file_path = resume.uploaded_file.path
                if not os.path.exists(resume_file_path):
                    logger.warning(f"上传文件不存在: {resume_file_path}")
                    resume_file_path = None
                else:
                    logger.info(f"使用上传文件: {resume_file_path}")
            except Exception as e:
                logger.warning(f"获取上传文件路径失败: {e}")

        # 构建岗位信息
        job_position = f"""
岗位名称：{job.title}
公司名称：{job.company.name}
工作地点：{job.work_location}
岗位要求：{job.requirements}
岗位职责：{job.responsibilities}
学历要求：{job.education_requirement or '不限'}
经验要求：{job.experience_requirement or '不限'}
技能要求：{job.required_skills or '无特殊要求'}
"""

        # 保存岗位信息
        resume.ai_evaluation_job_position = job_position
        resume.save()

        # 调用Dify服务进行评估
        logger.info("调用Dify服务进行AI评估")
        logger.info(f"岗位信息长度: {len(job_position)}")
        logger.info(f"简历内容长度: {len(resume_content)}")
        logger.info(f"简历文件路径: {resume_file_path}")

        dify_start_time = time.time()
        dify_response = dify_service.evaluate_resume(
            job_description=job_position,
            resume_content=resume_content,
            resume_file_path=resume_file_path,
            user_id=user_id
        )
        dify_elapsed = time.time() - dify_start_time
        logger.info(f"Dify服务调用完成，耗时: {dify_elapsed:.2f}秒")

        # 提取评估内容
        logger.info("开始提取评估内容")
        evaluation_content = dify_service.extract_evaluation_content(dify_response)
        logger.info(f"评估内容提取完成，长度: {len(evaluation_content) if evaluation_content else 0}")

        # 保存评估结果
        with transaction.atomic():
            resume.ai_evaluation_content = evaluation_content
            resume.ai_evaluation_status = 'completed'
            resume.ai_evaluation_at = timezone.now()
            resume.ai_evaluation_error = None

            # 生成评估报告文件
            file_name = f"ai_evaluation_{resume.id}_{timezone.now().strftime('%Y%m%d_%H%M%S')}.md"
            file_content = evaluation_content.encode('utf-8')
            resume.ai_evaluation_file.save(
                file_name,
                ContentFile(file_content),
                save=False
            )

            resume.save()

        elapsed_time = time.time() - start_time
        logger.info(f"AI评估完成 - Resume ID: {resume.id}, 耗时: {elapsed_time:.2f}秒")

        # 发送评估完成通知
        send_evaluation_notification(student_user, resume, job, 'completed')

        return {
            'success': True,
            'message': 'AI评估完成',
            'evaluation_status': resume.ai_evaluation_status,
            'evaluation_file_url': resume.ai_evaluation_file.url if resume.ai_evaluation_file else None,
            'evaluation_at': resume.ai_evaluation_at.isoformat() if resume.ai_evaluation_at else None,
            'elapsed_time': elapsed_time
        }
        
    except DifyAPIError as e:
        # Dify API调用失败
        elapsed_time = time.time() - start_time
        error_msg = f'Dify API调用失败: {str(e)}'
        logger.error(f"AI评估失败 - Resume ID: {resume_id}, {error_msg}, 耗时: {elapsed_time:.2f}秒")

        # 更新失败状态
        if resume:
            with transaction.atomic():
                resume.ai_evaluation_status = 'failed'
                resume.ai_evaluation_error = error_msg
                resume.save()

        # 如果是可重试的错误，进行重试
        if self.request.retries < self.max_retries:
            logger.info(f"AI评估任务重试 - Resume ID: {resume_id}, 重试次数: {self.request.retries + 1}")
            raise self.retry(countdown=60 * (self.request.retries + 1))

        # 最终失败，发送通知
        if resume and job:
            send_evaluation_notification(student_user, resume, job, 'failed', error_msg)

        return {'error': error_msg}

    except Exception as e:
        # 其他异常
        elapsed_time = time.time() - start_time
        error_msg = f'评估过程中发生异常: {str(e)}'
        logger.error(f"AI评估异常 - Resume ID: {resume_id}, {error_msg}, 耗时: {elapsed_time:.2f}秒")

        # 记录详细错误信息
        import traceback
        logger.error(f"详细错误信息: {traceback.format_exc()}")

        # 更新失败状态
        if resume:
            with transaction.atomic():
                resume.ai_evaluation_status = 'failed'
                resume.ai_evaluation_error = error_msg
                resume.save()

        # 如果是可重试的错误，进行重试
        if self.request.retries < self.max_retries:
            logger.info(f"AI评估任务重试 - Resume ID: {resume_id}, 重试次数: {self.request.retries + 1}")
            raise self.retry(countdown=60 * (self.request.retries + 1))

        # 最终失败，发送通知
        if resume and job:
            send_evaluation_notification(student_user, resume, job, 'failed', error_msg)

        return {'error': error_msg}

    except SoftTimeLimitExceeded:
        # 软超时处理
        elapsed_time = time.time() - start_time
        error_msg = f'AI评估任务软超时（9分钟），任务将被终止'
        logger.warning(f"AI评估软超时 - Resume ID: {resume_id}, 耗时: {elapsed_time:.2f}秒")

        # 更新状态为失败
        if resume:
            with transaction.atomic():
                resume.ai_evaluation_status = 'failed'
                resume.ai_evaluation_error = '评估任务超时，请重新尝试'
                resume.save()

        # 发送通知
        if resume and job:
            send_evaluation_notification(student_user, resume, job, 'failed', '评估任务超时，请重新尝试')

        return {'error': error_msg}




@shared_task(bind=True)
def cleanup_stuck_evaluations(self):
    """
    清理卡住的AI评估任务
    定期检查并重置长时间处于in_progress状态的评估任务
    """
    from django.utils import timezone
    from datetime import timedelta

    # 查找超过10分钟仍在进行中的评估任务
    stuck_time = timezone.now() - timedelta(minutes=10)
    stuck_resumes = Resume.objects.filter(
        ai_evaluation_status='in_progress',
        updated_at__lt=stuck_time
    )

    count = 0
    for resume in stuck_resumes:
        try:
            with transaction.atomic():
                # 将状态设置为 failed，但允许重新评估
                resume.ai_evaluation_status = 'failed'
                resume.ai_evaluation_error = '评估任务超时，已自动重置，可重新评估'
                resume.save()

            # 发送通知
            try:
                student_user = resume.student.user if hasattr(resume.student, 'user') else None
                if student_user:
                    send_evaluation_notification(
                        student_user, resume, None, 'failed',
                        '评估任务超时，请重新尝试评估'
                    )
            except Exception as e:
                logger.error(f"发送超时通知失败 - Resume ID: {resume.id}, Error: {e}")

            count += 1
            logger.info(f"重置卡住的评估任务 - Resume ID: {resume.id}")

        except Exception as e:
            logger.error(f"重置评估任务失败 - Resume ID: {resume.id}, Error: {e}")

    logger.info(f"清理完成，共重置 {count} 个卡住的评估任务")
    return {'cleaned_count': count}
